home *** CD-ROM | disk | FTP | other *** search
Korn shell script | 1997-08-26 | 5.1 KB | 189 lines |
- #!/bin/ksh
- # @(#) cbase.ksh 1.3 97/07/13
- # 11/08/90 john h. dubois iii (john@armory.com)
- # 91/02/13 cleaned up
- # 91/04/29 changed incorrect reference to xbase() to cbase()
- # 93/07/12 Added oO options and ksh input bases.
- # 94/01/01 Changed [oO] to [rR], added bBoOxX options.
- # 94/11/11 Added w, and W, and s options.
- # 95/07/25 Added i option.
- # 97/07/13 Send error messages to stderr.
-
- alias istrue="test 0 -ne"
- alias isfalse="test 0 -eq"
-
- # Usage: SplitWord wordsize value
- # Low bits are put in SplitWord[0], etc.
- # The number of words put in SplitWord[] is returned
- # (this is one more than the highest index in SplitWord[])
- typeset -i SplitWord
- function SplitWord {
- typeset -i WordSize=$1 Value=$2 i=0 Mask ShiftMask
-
- unset SplitWord[*]
- ((Mask=(1<<WordSize)-1)) # Mask for getting low WordSize bits
- # ShiftMask is used to get rid of the 1s that are shifted in for negative
- # numbers.
- (( ShiftMask=~(Mask<<(32-WordSize)) ))
- while [ Value -ne 0 ]; do
- ((SplitWord[i]=Value&Mask))
- ((Value=(Value>>WordSize)&ShiftMask))
- let i+=1
- done
- return $i
- }
-
- # cbase: convert C-style and ksh-style constants to decimal numbers
- # convert hex (0xn and 0Xn), octal (0n), decimal or default, ksh (b#n)
- # to decimal & print
- # Globals: if defBase is set to a positive value, it is the default base
- # to use for values that are not hex or ksh-base constants.
- # If defBase is not set, values of the form 0n are taken to be octal;
- # if it is set, they are taken to be values in the default base.
- cbase() {
- typeset -i$obase d
- typeset -i i words Inc
- typeset bits out
-
- while [ $# -gt 0 ]; do
- if [[ defBase -gt 0 && "$1" = +([0-9a-zA-Z]) ]]; then
- d=$defBase#$1 || {
- shift
- continue
- }
- else
- case $1 in
- 0[xX]*([0-9a-fA-F]) ) d=16#${1#0[xX]};; # C style hex
- 0*([0-7]) ) d=8#$1;; # C style octal
- [1-9]*([0-9]) ) d=$1;; # decimal default
- +([0-9])#+([0-9]) ) d=$1;; # ksh style base
- *) print -ru2 -- "$name: Bad number: $1"
- shift
- continue
- ;;
- esac
- fi
- if [ WordSize -lt 32 ]; then
- SplitWord $WordSize $d
- words=$?
- if istrue BigEndian; then
- Start=words-1
- End=-1
- Inc=-1
- else
- Start=0
- End=words
- Inc=1
- fi
- bits=
- while [ Start -ne End ]; do
- d=SplitWord[Start]
- istrue nobase &&
- bits="$bits$Sep${d#+([0-9])#}" || bits="$bits$Sep$d"
- let Start+=Inc
- done
- out="$out ${bits#?}" # get rid of initial Sep
- else
- istrue nobase && out="$out ${d#+([0-9])#}" || out="$out $d"
- fi
- shift
- done
- [ -n "$out" ] && print -- $out
- }
-
- typeset -i obase=10 nobase=0 WordSize=32 BigEndian=0 defBase=0
- Sep=' '
-
- name=${0##*/}
- Usage=\
- "Usage: $name [-hbBoOxX] [-i<in-base>] [-[rR]<out-base>] <integer value> ..."
-
- while getopts :hr:R:bBoOxXw:W:s:i: opt; do
- case $opt in
- h)
- print -r -- \
- "$name: convert integers between bases.
- $Usage
- Octal, decimal, and hexadecimal values may be given using C notation (nnn,
- 0nnn, and 0xnnn/0Xnnn) respectively). A value may also be entered in any base
- between 2 and 2^32-1 using ksh notation (base#value, e.g. 7#33 to enter a
- value in base 7).
- If no numbers are given on the command line, they are read from the input
- until end of file is reached.
- Options:
- -h: Print this help.
- -r<out-base>: Change the output base (radix) to <base>; must be in range 2..36.
- -b: Change the output base to 2 (binary).
- -o: Change the output base to 8 (octal).
- -x: Change the output base to 16 (hex).
- -R<out-base>, -B, -O, -X: Like the lower case options, except that the output
- will not include base specifiers.
- -i<in-base>: Change the default input base from decimal to <in-base>. This
- affects values not given in hex (0xnnn) or ksh (b#nnn) notation. If -i is
- given, values that begin with 0 are taken to be in the specified base,
- rather than octal.
- -w<wordsize>: Change the word size to <wordsize> bits. Any values entered
- which have more than <wordsize> bits will be split up into multiple words.
- The word representing the high <wordsize> bits is printed first, but the
- word is split starting from the right, which affects the grouping of
- bits when <wordsize> is not a power of two.
- -W<wordsize>: Like -w, but the word representing the low <wordsize> bits is
- printed first.
- -s<sep>: Set the separator string for words split according to the w and W
- options. By default, the components are separated with a space."
- exit 0
- ;;
- i)
- defBase=$OPTARG || exit 1
- ;;
- [rR])
- obase=$OPTARG || exit 1
- ;;
- [bB])
- obase=2
- ;;
- [oO])
- obase=8
- ;;
- [xX])
- obase=16
- ;;
- [wW])
- WordSize=$OPTARG || exit 1
- if [ WordSize -lt 1 ]; then
- print -ru2 -- "$name: Bad word size: $OPTARG"
- exit 1
- fi
- [ $opt = w ] && BigEndian=1
- ;;
- s)
- Sep=$OPTARG;;
- +?)
- print -ru2 -- "$name: options should not be preceded by a '+'."
- exit 1
- ;;
- :)
- print -ru2 -- \
- "$name: Option '$OPTARG' requires a value. Use -h for help."
- exit 1
- ;;
- ?)
- print -ru2 -- "$name: $OPTARG: bad option. Use -h for help."
- exit 1
- ;;
- esac
- [[ $opt = [A-Z] ]] && nobase=1
- done
-
- # remove args that were options
- let OPTIND=OPTIND-1
- shift $OPTIND
-
- if [ $# -gt 0 ]; then
- cbase $*
- else
- while read line; do
- cbase $line
- done
- fi
-